package net.moonbiter.ebs.protocols.httpjava.client;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import org.apache.log4j.Logger;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import net.moonbiter.ebs.ServiceProviderDef;
import net.moonbiter.ebs.ServicesRegister;

public class JarGenerator {
	private static final Logger logger = Logger.getLogger(JarGenerator.class);
	private ClassPool pool;
	
	public JarGenerator() {
		pool = ClassPool.getDefault();
	}
	
	public void appendClassPathEntry(String path) throws NotFoundException{
		pool.appendClassPath(path);
	}
	
	public void insertClassPathEntry(String path) throws NotFoundException{
		pool.insertClassPath(path);
	}	
	
	private static String toFileName(String className){
		String slashed = className.replaceAll("\\.", "/");
		return slashed+".class";
	}
	
	public void generateClientJar(ServicesRegister services, 
			String packageName, OutputStream out) throws CannotCompileException, IOException {
		ByteArrayOutputStream bo = null;
		JarOutputStream jo = null;
		SourceGenerator srcGen = new SourceGenerator(this.pool);
		List<CtClass> generatedClasses = srcGen.generateAll(packageName, services);
		logger.debug("Class files to insert in jar: "+generatedClasses);
		try {
			bo = new ByteArrayOutputStream();
			Manifest manifest = new Manifest();
			jo = new JarOutputStream(out, manifest);
			
			for (CtClass generatedClass : generatedClasses){				
				String fileName = toFileName(generatedClass.getName());
				logger.debug("adding entry for class file \""
						+generatedClass.getName()+"\", in filename \""+fileName+"\"");
				JarEntry je = new JarEntry(fileName);
				jo.putNextEntry(je);

				byte[] bytes = generatedClass.toBytecode();
				jo.write(bytes, 0, bytes.length);
				jo.flush();
			}
		} finally {
			if (jo!=null) jo.close();
			if (bo!=null) bo.close();
		}
	}		
}
